//
//  MotionAndLocationManager.m
//  记步-Demo
//
//  Created by qinlongqing on 14/11/10.
//  Copyright (c) 2014年 qinlongqing. All rights reserved.
//

#import "MotionAndLocationManager.h"
#import "UserManager.h"
#import <HealthKit/HealthKit.h>

CGFloat kMinAccelerometer = 1.03;//最小用于标示一步的重力加速度
NSTimeInterval kMaxCheckTimeInterval = 7;//检测时间间隔

CGFloat kMinWalkingSpeed = 0.30f;//最小的步行速度
CGFloat kMaxWalkingSpeed = 3.00f;//最大的步行速度
CGFloat kMinWalkingDistance = 2.00;//最小的移动距离

static NSInteger firstUpdateLocation = 0;//标示是否是第一次定位


#define debug 1


@interface MotionAndLocationManager ()<CLLocationManagerDelegate>
{
//    CLLocationManager *locationManager;
    
    CMMotionManager *motionManager;//加速器对象
    
//    CMMotionActivityManager *motionActivityManager;//当M7时，加速器活动控制者
    CMPedometer *pedometer;//当M7处理器可用时，调用这里面的数据

    NSTimer *checkIsWalkingTimer;//检测在这10s内有没位置更新，如果有位置更新，并且移动速度小于步行的最大速度,则存储移动的步数,并再次从0s开始检测;如果在这10s内没有位置更新，则移除存储的步数,并再次从0s开始计时。
    
//    NSInteger currentSteps;//初始化时，取出数据库中记录的数据，当每次达到步行时的加速度时，加1
    NSMutableArray *allStepsInThisDayArray;//一天之内所有的步数
    
    NSMutableArray *stepsBeforeUpdataLocationOrInTenSecondArray;//暂时存储步数
    
    
#ifdef debug
//    NSMutableArray *motionDataArray;//。。。。。。。。
//    NSMutableArray *locationDataArray;//。。。。。。。。
#endif
}

@property (nonatomic,assign) CLLocationManager *locationManager;//必须声明为属性

@property (nonatomic,retain) CLLocation *lastLocation;
@property (nonatomic,retain) CLLocation *previouseLocation;


@end

@implementation MotionAndLocationManager

+ (MotionAndLocationManager *)sharedInstance{
    static MotionAndLocationManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc]init];
    });
    return instance;
}

+ (void)deallocInstance{
    [MotionAndLocationManager sharedInstance].delegate = nil;
    [[MotionAndLocationManager sharedInstance] stop];
//    [[MotionAndLocationManager sharedInstance] release];//此处有崩溃，不能release
}

- (instancetype)init{
    self = [super init];
    if (self) {
        if (motionManager == nil) {
            motionManager = [[CMMotionManager alloc]init];
        }
    }
    return self;
}

- (BOOL)isLocationAvailable{
    if (IOS8_OR_LATER) {
        if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)){
            return YES;
        }
    }
    else{
        if ([CLLocationManager locationServicesEnabled] && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)){
            return YES;
        }
    }
    return NO;
}

- (BOOL)isM7StepsDataAvailable{
    if ([CMStepCounter isStepCountingAvailable] && [CMPedometer isStepCountingAvailable]) {
        return YES;
    }
    return NO;
}

- (void)start{
    //如果是iPhone5s以上
    if (self.isM7Support) {//当M7可以用时
//        if (!motionActivityManager) {
//            motionActivityManager = [[CMMotionActivityManager alloc]init];
//        }
//        [motionActivityManager startActivityUpdatesToQueue:[[NSOperationQueue alloc]init] withHandler:^(CMMotionActivity *activity) {
//        
//        }];
        //开启记步时，得到这一天内的所有步数
        dispatch_async(dispatch_get_main_queue(), ^{
            //得到所走的步数
            if (self.delegate && [self.delegate respondsToSelector:@selector(motionAndLocationManagerUpdataCurrentStepsDetailFrom_M7:)]) {
                [self.delegate motionAndLocationManagerUpdataCurrentStepsDetailFrom_M7:self];
            }
        });
        
        if (!pedometer) {
            pedometer = [[CMPedometer alloc]init];
        }
        [pedometer startPedometerUpdatesFromDate:[NSDate date] withHandler:^(CMPedometerData *pedometerData, NSError *error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                //得到所走的步数
                if (self.delegate && [self.delegate respondsToSelector:@selector(motionAndLocationManagerUpdataCurrentStepsDetailFrom_M7:)]) {
                    [self.delegate motionAndLocationManagerUpdataCurrentStepsDetailFrom_M7:self];
                }
            });
        }];
    }
    else{
        //开启记步时，得到这一天内的所有步数
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
        [dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
        NSString *yyyyMMdd = [[dateFormatter stringFromDate:[NSDate date]] substringToIndex:8];
        NSString *fromDateString = [yyyyMMdd stringByAppendingFormat:@"000000"];
        NSString *toDateString = [yyyyMMdd stringByAppendingFormat:@"235959"];
        NSDate *fromDate = [dateFormatter dateFromString:fromDateString];
        NSDate *toDate = [dateFormatter dateFromString:toDateString];
        allStepsInThisDayArray = [[[MotionAndLocationManager sharedInstance] getStepFromDate:fromDate toDate:toDate] mutableCopy];
        [dateFormatter release];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.delegate && [self.delegate respondsToSelector:@selector(motionAndLocationManager:updataCurrentStepsDetailFrom_DB:)]) {
                [self.delegate motionAndLocationManager:self updataCurrentStepsDetailFrom_DB:allStepsInThisDayArray];
            }
        });
        
        if (stepsBeforeUpdataLocationOrInTenSecondArray == nil) {
            stepsBeforeUpdataLocationOrInTenSecondArray = [[NSMutableArray alloc]init];//缓存每一步的时间
        }
        
#pragma 开启定位服务
        self.locationManager = [[CLLocationManager alloc]init];
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        self.locationManager.distanceFilter = kCLDistanceFilterNone;
        self.locationManager.delegate = self;
        if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
            [self.locationManager requestAlwaysAuthorization];
        }
        [self.locationManager startUpdatingLocation];
        
#pragma 开启加速度
        if (motionManager == nil) {
            motionManager = [[CMMotionManager alloc]init];
        }
        motionManager.accelerometerUpdateInterval = 0.5f;
        [motionManager startAccelerometerUpdatesToQueue:[[NSOperationQueue alloc]init] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
            if (firstUpdateLocation == 1) {//从第一次定位以后开始缓存每一步
                double accX_2 = powf(accelerometerData.acceleration.x, 2);//float powf(float x, float y);x的y次幂
                double accY_2 = powf(accelerometerData.acceleration.y, 2);
                double accZ_2 = powf(accelerometerData.acceleration.z, 2);
                double vectorSum = sqrtl(accX_2 + accY_2 + accZ_2);//开平方
                
#ifdef debug
//                NSDate *currentDate = [NSDate date];
//                NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
//                [dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
//                NSString *timeString = [dateFormatter stringFromDate:currentDate];
//                NSString *motionString = [NSString stringWithFormat:@"----motionUpdata---- time = %@  vectorSum = %f  X = %f  Y = %f  Z = %f",timeString,vectorSum,accelerometerData.acceleration.x,accelerometerData.acceleration.y,accelerometerData.acceleration.z];
//                [motionDataArray addObject:motionString];
#endif

                if (vectorSum >= kMinAccelerometer) {
                    NSDate *currentDate = [NSDate date];
                    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[self getCurrentUserID],kCurrentUserID,currentDate,kTimeForCurrentStep, nil];
                    [stepsBeforeUpdataLocationOrInTenSecondArray addObject:dict];
                }
            }
        }];
        
        
        
#ifdef debug
//        if (motionDataArray == nil) {
//            motionDataArray = [[NSMutableArray alloc]init];
//        }
//        if (locationDataArray == nil) {
//            locationDataArray = [[NSMutableArray alloc]init];
//        }
#endif
    }
}

static NSInteger checkCount = 0;
- (void)checkIsWalking{
    if (checkCount < kMaxCheckTimeInterval) {
        checkCount++;
    }
    if (checkCount == kMaxCheckTimeInterval) {
        MyNSLog("定位超时,数据已删除,删除条数=%d",[stepsBeforeUpdataLocationOrInTenSecondArray count]);

        @synchronized(self){
            [stepsBeforeUpdataLocationOrInTenSecondArray removeAllObjects];
            checkCount = 0;
        }
    }
}

- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
    switch (status) {
        case kCLAuthorizationStatusNotDetermined:{
            if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
                [self.locationManager requestAlwaysAuthorization];
            }
            break;
        }
        default:
            break;
    } 
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
    self.lastLocation = [locations lastObject];
    MyNSLog("定位一次");
    if (firstUpdateLocation == 0) {
        firstUpdateLocation = 1;
        if (checkIsWalkingTimer == nil) {
            checkIsWalkingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(checkIsWalking) userInfo:nil repeats:YES];
        }
    }
    else if (firstUpdateLocation == 1) {
        if (self.lastLocation.speed > 0.0) {
            
#ifdef debug
//            CLLocationDistance distance = [self.lastLocation distanceFromLocation:self.previouseLocation];
//            NSTimeInterval lastMovedTime = [self.lastLocation.timestamp timeIntervalSinceDate:self.previouseLocation.timestamp];
//            NSDate *currentDate = [NSDate date];
//            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
//            [dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
//            NSString *timeString = [dateFormatter stringFromDate:currentDate];
//            NSString *lastString = [NSString stringWithFormat:@"---locationUpdata--- time = %@  distance = %f  lastMovedTime = %f  currentSpeed = %f \n",timeString,distance,lastMovedTime,self.lastLocation.speed];
//            [locationDataArray addObject:lastString];
#endif
            
            if (self.lastLocation.speed > kMinWalkingSpeed && self.lastLocation.speed < kMaxWalkingSpeed) {
                MyNSLog("插入数据库,条数=%d",[stepsBeforeUpdataLocationOrInTenSecondArray count]);
                //把缓存的步数存到数据库
                [[StepCountDBManager sharedInstance] insertStepsDataWithArray:stepsBeforeUpdataLocationOrInTenSecondArray successOrFailBlock:^(BOOL isSuccess) {
                    if (isSuccess) {//存储成功
                        @synchronized(allStepsInThisDayArray){
                            [allStepsInThisDayArray addObjectsFromArray:stepsBeforeUpdataLocationOrInTenSecondArray];//当把缓存的每一步写到数据库后，再插入本地存储数组
                        }
                        @synchronized(stepsBeforeUpdataLocationOrInTenSecondArray){
                            [stepsBeforeUpdataLocationOrInTenSecondArray removeAllObjects];
                            checkCount = 0;
                        }
                        dispatch_async(dispatch_get_main_queue(), ^{
                            if (self.delegate && [self.delegate respondsToSelector:@selector(motionAndLocationManager:updataCurrentStepsDetailFrom_DB:)]) {
                                [self.delegate motionAndLocationManager:self updataCurrentStepsDetailFrom_DB:allStepsInThisDayArray];
                            }
                        });
                    }
                    else{//存储失败
                        checkCount = 0;
                    }
                }];
            }
        }
        else{
            //通过两次定位的距离和时间，计算出当前的速度
            CLLocationDistance distance = [self.lastLocation distanceFromLocation:self.previouseLocation];
            NSTimeInterval lastMovedTime = [self.lastLocation.timestamp timeIntervalSinceDate:self.previouseLocation.timestamp];
            CGFloat currentSpeed = distance/lastMovedTime;
            if (currentSpeed < 0.0) {
                currentSpeed = 0.0;
            }
            
            
#ifdef debug
//            NSDate *currentDate = [NSDate date];
//            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
//            [dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
//            NSString *timeString = [dateFormatter stringFromDate:currentDate];
//            NSString *lastString = [NSString stringWithFormat:@"---locationUpdata--- time = %@  distance = %f  lastMovedTime = %f  currentSpeed = %f \n",timeString,distance,lastMovedTime,currentSpeed];
//            [locationDataArray addObject:lastString];
#endif
            
        
            if (currentSpeed > kMinWalkingSpeed && currentSpeed < kMaxWalkingSpeed) {
                MyNSLog("插入数据库,条数=%d",[stepsBeforeUpdataLocationOrInTenSecondArray count]);
                //把缓存的步数存到数据库
                [[StepCountDBManager sharedInstance] insertStepsDataWithArray:stepsBeforeUpdataLocationOrInTenSecondArray successOrFailBlock:^(BOOL isSuccess) {
                    if (isSuccess) {
                        @synchronized(allStepsInThisDayArray){
                            [allStepsInThisDayArray addObjectsFromArray:stepsBeforeUpdataLocationOrInTenSecondArray];//当把缓存的每一步写到数据库后，再插入本地存储数组
                        }
                        @synchronized(stepsBeforeUpdataLocationOrInTenSecondArray){
                            [stepsBeforeUpdataLocationOrInTenSecondArray removeAllObjects];
                            checkCount = 0;
                        }
                        dispatch_async(dispatch_get_main_queue(), ^{
                            if (self.delegate && [self.delegate respondsToSelector:@selector(motionAndLocationManager:updataCurrentStepsDetailFrom_DB:)]) {
                                [self.delegate motionAndLocationManager:self updataCurrentStepsDetailFrom_DB:allStepsInThisDayArray];
                            }
                        });
                    }
                    else{
                        checkCount = 0;
                    }
                }];
            }
        }
    }
    self.previouseLocation = self.lastLocation;
}

- (NSString *)getCurrentUserID{
    NSString *isLogin = [NSString stringWithFormat:@"%@",[[UserManager shareInstance] getUserIsLogin]];;
    if (isLogin) {
        return [[UserManager shareInstance] getUserInfo].uid;
    }
    return @"匿名";
}

- (void)stop{
    checkCount = 0;
    firstUpdateLocation = 0;
    self.lastLocation = nil;
    self.previouseLocation = nil;
    
    
    if (pedometer) {
        [pedometer stopPedometerUpdates];
        [pedometer release];
        pedometer = nil;
    }
    
    if (checkIsWalkingTimer) {
        [checkIsWalkingTimer invalidate];
        checkIsWalkingTimer = nil;
    }

    if (self.locationManager) {
        [self.locationManager stopUpdatingLocation];
        [self.locationManager release];
        self.locationManager = nil;
    }
    
    if (motionManager) {
        [motionManager stopAccelerometerUpdates];
        [motionManager release];
        motionManager = nil;
    }
    
    if (stepsBeforeUpdataLocationOrInTenSecondArray) {
        [stepsBeforeUpdataLocationOrInTenSecondArray removeAllObjects];
        [stepsBeforeUpdataLocationOrInTenSecondArray release];
        stepsBeforeUpdataLocationOrInTenSecondArray = nil;
    }
    if (allStepsInThisDayArray) {
        [allStepsInThisDayArray removeAllObjects];
        [allStepsInThisDayArray release];
        allStepsInThisDayArray = nil;
    }
    
#ifdef debug
//    [self writeToFileFromCurrentAcc];
//    [self writeToFileFromCurrentLocation];
//    if (motionDataArray) {
//        [motionDataArray removeAllObjects];
//        [motionDataArray release];
//        motionDataArray = nil;
//    }
//    if (locationDataArray) {
//        [locationDataArray removeAllObjects];
//        [locationDataArray release];
//        locationDataArray = nil;
//    }
#endif
}

- (id)getStepFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate{
    if ([toDate compare:fromDate] == NSOrderedDescending) {
        if (self.isM7Support) {
            if (!pedometer) {
                pedometer = [[CMPedometer alloc]init];
            }
            [pedometer queryPedometerDataFromDate:fromDate toDate:toDate withHandler:^(CMPedometerData *pedometerData, NSError *error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (self.delegate && [self.delegate respondsToSelector:@selector(motionAndLocationManagerGetPedometerDataInAnHour:)]) {
                        [self.delegate motionAndLocationManagerGetPedometerDataInAnHour:pedometerData];
                    }
                });
            }];
        }
        else{
            return [[StepCountDBManager sharedInstance] selectStepsCountFromDate:fromDate toDate:toDate WithUserID:[self getCurrentUserID]];
        }
    }
    return 0;
}

- (NSUInteger)getAllStepsForDay:(NSString *)yyyyMMdd{
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setDateFormat:@"yyyyMMddHHmmss"];
    NSString *fromDateString = [yyyyMMdd stringByAppendingFormat:@"000000"];
    NSString *toDateString = [yyyyMMdd stringByAppendingFormat:@"235959"];
    NSDate *fromDate = [dateFormatter dateFromString:fromDateString];
    NSDate *toDate = [dateFormatter dateFromString:toDateString];

    if ([toDate compare:fromDate] == NSOrderedDescending) {
        if (self.isM7Support) {
            if (!pedometer) {
                pedometer = [[CMPedometer alloc]init];
            }
            [pedometer queryPedometerDataFromDate:fromDate toDate:toDate withHandler:^(CMPedometerData *pedometerData, NSError *error) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (self.delegate && [self.delegate respondsToSelector:@selector(didGetAllSteps:forDay:)]) {
                        NSUInteger allSteps = [pedometerData.numberOfSteps unsignedIntegerValue];
                        [self.delegate didGetAllSteps:allSteps forDay:yyyyMMdd];
                    }
                });
            }];
        }
        else{
            NSMutableArray *allStepsTime = [[StepCountDBManager sharedInstance] selectStepsCountFromDate:fromDate toDate:toDate WithUserID:[self getCurrentUserID]];
            return allStepsTime.count;
        }
    }
    return 0;
}


- (void)dealloc{
    [self stop];
    
    [super dealloc];
}

- (void)writeToFileFromCurrentAcc{
#ifdef debug
//    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"accLog.xml"];
//    for (int i=0; i<motionDataArray.count; i++) {
//        NSString *currentFileContent = @"";
//        NSFileManager *fm = [NSFileManager defaultManager];
//        if ([fm fileExistsAtPath:filePath]) {
//            currentFileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
//        }
//        currentFileContent = [currentFileContent stringByAppendingFormat:@"%@",[motionDataArray objectAtIndex:i]];
//        [currentFileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
//    }
#endif
}

- (void)writeToFileFromCurrentLocation{
#ifdef debug
//    NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"locationLog.xml"];
//    
//    for (int i=0; i<locationDataArray.count; i++) {
//        NSString *currentFileContent = @"";
//        NSFileManager *fm = [NSFileManager defaultManager];
//        if ([fm fileExistsAtPath:filePath]) {
//            currentFileContent = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
//        }
//        currentFileContent = [currentFileContent stringByAppendingFormat:@"%@",[locationDataArray objectAtIndex:i]];
//        [currentFileContent writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
//    }
#endif
}


@end
